<template>
    <div class="markdown-box" :style="{ height: height }">
        <mavon-editor :codeStyle="codeStyle" :placeholder="placeholder" v-if="!isPreview" :toolbars="mdOption"
            v-model="content" @change="changeVaule" @sava="sava" @imgAdd="$imgAdd" :ishljs="ishljs" :fontSize="fontSize"
            v-bind="options" :previewBackground="previewBackground"></mavon-editor>
        <mavon-editor :class="{aiStream : aiStream}" :codeStyle="codeStyle" v-else class="content" v-model="content" :navigation="false"
            :toolbarsFlag="false" :subfield="false" defaultOpen="preview"
            :previewBackground="previewBackground"></mavon-editor>
    </div>
</template>
<script lang="ts" setup>
import { ref, defineOptions, watch } from "vue";
import type { PropType } from 'vue'

import type {codeStyleInstance , streamListInstance} from "./@types"

defineOptions({
    name: "dzsMarkdown"
})

import "mavon-editor/dist/css/index.css";
import mavonEditorModule from "mavon-editor";
const mavonEditor = mavonEditorModule.mavonEditor;
const emit = defineEmits(["update:value", "onSave", 'change'])

const props = defineProps({
    // 输入框的提示词
    placeholder: {
        type: String,
        default: "请输入..."
    },
    /**样式*/
    codeStyle: {
        type: String as PropType<codeStyleInstance>,
        default: "dark"
    },
    options: {
        type: Object,
        default: () => {
            return {}
        }
    },
    value: {
        type: String,
        default: () => {
            return "";
        },
    },
    height: {
        type: String,
        default: () => {
            return "auto";
        },
    },
    width: {
        type: String,
        default: () => {
            return "100%";
        },
    },
    ishljs: {
        type: Boolean,
        default: () => {
            return true;
        },
    },
    fontSize: {
        type: String,
        default: () => {
            return '14px'
        }
    },
    /**是否只需要预览*/
    isPreview: {
        type: Boolean,
        default: () => {
            return false;
        },
    },
    /**预览背景*/
    previewBackground: {
        type: String,
        default: () => {
            return '#ffffff'
        }
    },
    markdownOption: {
        type: Object,
        default: () => {
            return {
                bold: true, // 粗体
                italic: true, // 斜体
                header: true, // 标题
                underline: true, // 下划线
                strikethrough: true, // 中划线
                mark: true, // 标记
                superscript: true, // 上角标
                subscript: true, // 下角标
                quote: true, // 引用
                ol: true, // 有序列表
                ul: true, // 无序列表
                link: true, // 链接
                imagelink: true, // 图片链接
                code: true, // code
                table: true, // 表格
                fullscreen: true, // 全屏编辑
                readmodel: true, // 沉浸式阅读
                htmlcode: true, // 展示html源码
                help: true, // 帮助
                /* 1.3.5 */
                undo: true, // 上一步
                redo: true, // 下一步
                trash: true, // 清空
                save: true, // 保存（触发events中的save事件）
                /* 1.4.2 */
                navigation: true, // 导航目录
                /* 2.1.8 */
                alignleft: true, // 左对齐
                aligncenter: true, // 居中
                alignright: true, // 右对齐
                /* 2.2.1 */
                subfield: true, // 单双栏模式
                preview: true, // 预览
            };
        },
    },

    /**大模型 流数据*/
    streamList: {
        type: Array<streamListInstance>,
        default: function () {
            return []
        }
    },
    /**是否开启 AI 流模式*/
    aiStream: {
        type: Boolean,
        default: () => {
            return false
        }
    },
})
const content = ref("");
const mdOption = ref(props.markdownOption);
const resultText = ref("");
const printTimer = ref<number | null>(null);
const changeVaule = () => {
    let resultText = content.value.replace(/'/g, "&#39;");
    emit("update:value", resultText);
    emit("change", resultText);
}
const sava = () => {
    let resultText = content.value.replace(/'/g, "&#39;");
    emit("update:value", resultText);
    emit("onSave", resultText);
}
const $imgAdd = (pos: any, $file: File) => {
    let formdata = new FormData();
    formdata.append("image", $file);
}
/**打印机效果*/
const startTypingEffect = (printIndex: number = 0) => {
    let data : streamListInstance | {} = {};
    const isStreamListInstance = (item: any): item is streamListInstance => {
        return typeof item === 'object' && item !== null && 'message' in item;
    };

    printTimer.value = setInterval(() => {
        if (props.streamList[printIndex]) {
            data = props.streamList[printIndex] as streamListInstance;
            clearInterval(printTimer.value as number);
            printTimer.value = null;
            if (isStreamListInstance(data) && data.end) {
                printEnd()
                return;
            }
            requestAnimationFrame(printNextChar);
        }
    }, 50);
    const printNextChar = () => {
        if (!isStreamListInstance(data) || !data.message) {
            startTypingEffect(printIndex + 1);
            return;
        }
        if (data.message.length === 0) {
            data.end && printEnd();
            startTypingEffect(printIndex + 1)
            return;
        }
        let char = data.message[0];
        data.message = data.message.slice(1);
        resultText.value += char;
        content.value = resultText.value;
        requestAnimationFrame(printNextChar);
        data.end && printEnd();
    };
}

/**打印结束*/
const printEnd = () => {
    setTimeout(() => {
        content.value = resultText.value
    }, 500);
}


watch(() => props.value, (newValue) => {
    if(content.value == newValue.replace(/&#39;/g, "'")) return;
    content.value = newValue ? newValue : "";
    content.value = content.value.replace(/&#39;/g, "'");
}, {
    immediate: true,
    deep: true,
})

watch(() => props.aiStream , (newValue) => { 
    newValue && startTypingEffect()
},{
    immediate: true,
    deep: true
})

</script>
<style lang="scss" scoped>
.markdown-box {
    :deep(.v-note-wrapper) {
        height: 100%;
        z-index: 10;
    }

    :deep(.markdown-body .hljs) {
        padding: 10px;
        border-radius: 10px;
    }
    .aiStream{
        min-width: none;
        min-height: auto;
    }
}
</style>